﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PasteLoggerBoard.Controllers;
using PasteLoggerBoard.redismodel;
using PasteLoggerBoard.usermodels;

namespace PasteLoggerBoard.HttpApi.Host.Controllers
{
    /// <summary>
    /// 
    /// </summary>
    [ApiController]
    [Route("/api/app/[controller]/[action]")]
    public class UserController : IBaseController
    {

        private IAppCache _cache => LazyServiceProvider.LazyGetRequiredService<IAppCache>();
        private ImageHelper _imageHelper => LazyServiceProvider.LazyGetRequiredService<ImageHelper>();
        private ModelHelper _modelHelper => LazyServiceProvider.LazyGetRequiredService<ModelHelper>();


        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbContext"></param>
        public UserController(IPasteLoggerBoardDbContext dbContext) : base(dbContext)
        {
        }

        /// <summary>
        /// 获取验证码
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        [HttpGet]
        public FileContentResult Image(string guid)
        {
            try
            {
                if (String.IsNullOrEmpty(guid))
                {
                    throw new Exception("验证码代码错误，guid不能为空!");
                }

                //进行特殊符号的替换工作
                if (!new System.Text.RegularExpressions.Regex("[0-9,a-z,A-Z]{16}").Match(guid).Success)
                {
                    throw new Exception("guid的位数不足，应为16位随机数，不能包含特殊符号，需要为字母和数字的组合");
                }

                if (_cache.Exists($"{PublicString.CacheImageHead}{guid}")) { throw new Exception("guid不能重复使用！"); }

                //判断guid是否存在

                string code = _imageHelper.CreateVerifyCode(ImageHelper.VerifyCodeType.NumberVerifyCode);

                _cache.Set($"{PublicString.CacheImageHead}{guid}", code, 300);

                byte[] codeImage = _imageHelper.CreateByteByImgVerifyCode(code, 80, 36);

                return File(codeImage, @"image/jpeg");
            }
            catch (Exception exl)
            {
                Logger.LogException(exl);
                throw new Exception(exl.Message);
            }
        }


        /// <summary>
        /// 登入
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        [HttpPost]
        public async Task<dynamic> Login(InputLogin input)
        {

            var codeval = await _cache.GetAsync($"{PublicString.CacheImageHead}{input.guid}");
            if (string.IsNullOrEmpty(codeval))
            {
                throw new PasteLoggerBoardException("图形验证码超时，请重新刷新！");
            }
            if (codeval != input.code)
            {
                _cache.Delete($"{PublicString.CacheImageHead}{input.guid}");
                throw new PasteLoggerBoardException("图形验证码错误，请重新输入！");
            }
            else
            {
                _cache.Delete($"{PublicString.CacheImageHead}{input.guid}");
            }

            var user = await _dbContext.UserInfo.Where(x => x.Email == input.Email).AsNoTracking().FirstOrDefaultAsync();
            if (user == null || user == default)
            {
                throw new PasteLoggerBoardException("不存在的邮箱账号，请重试！");
            }
            else
            {
                if (!user.IsEnable)
                {
                    throw new PasteLoggerBoardException("账号被封禁，请联系管理员");
                }

                if (user.PassWord != input.Password.ToMd5Lower())
                {
                    throw new PasteLoggerBoardException("密码错误，请重新输入");
                }

                if (String.IsNullOrEmpty(user.Grade))
                {
                    throw new PasteLoggerBoardException("当前账号未分配角色信息，请先分配后再试！");
                }

                //判定角色是否存在，然后读取权限列表

                var time = DateTimeOffset.Now.AddDays(3).ToUnixTimeSeconds();
                var temptoken = $"{time}_{user.Id}_{PublicString.TokenKey}".ToMd5Lower();
                var token = $"{time}_{user.Id}_{temptoken}";

                //值需要记录这个账号对应的角色即可
                //通过二次缓存，可以读取权限列表信息
                var roles = _dbContext.RoleInfo.Where(x => _dbContext.GradeRole.Where(x => x.GradeId == user.GradeId).Select(x => x.RoleId).Contains(x.Id)).AsNoTracking().ToList();
                if (roles != null && roles.Count > 0)
                {
                    var rolesdto = ObjectMapper.Map<List<RoleInfo>, List<RoleInfoListDto>>(roles);
                    //缓冲72小时
                    _cache.Set<List<RoleInfoListDto>>(token, rolesdto, PublicString.TokenTimeOut);
                }
                else
                {
                    throw new PasteLoggerBoardException("未为当前账号分配权限，无法进行登陆操作，请联系管理员分配权限后再试！");
                }

                return new
                {
                    name = user.UserName,
                    token = token
                };

            }


        }

        /// <summary>
        /// 登出
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<int> LoginOut()
        {
            if (base.HttpContext.Request.Headers.ContainsKey(PublicString.TokenHeadName))
            {
                var token = base.HttpContext.Request.Headers[PublicString.TokenHeadName].ToString();
                await _cache.DeleteAsync(token);
            }
            return 1;
        }

        ///// <summary>
        ///// 绑定或移除某一个用户和某一个部门或者组的关系
        ///// </summary>
        ///// <param name="userid"></param>
        ///// <param name="partid"></param>
        ///// <param name="state"></param>
        ///// <returns></returns>
        ///// <exception cref="PasteLoggerBoardException"></exception>
        //[HttpPost]
        //[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "read" })]
        //public async Task<int> UpdateUserPart(int userid, int partid, bool state)
        //{
        //    var user = await _modelHelper.ItemUserInfo(userid);
        //    if (user == null || user == default)
        //    {
        //        throw new PasteLoggerBoardException("没有这个用户信息");
        //    }

        //    //var group = await _modelHelper.ItemPartInfo(partid);
        //    //if (group == null || group == default)
        //    //{
        //    //    throw new PasteLoggerBoardException("没有这个部门分组信息");
        //    //}

        //    //var find = _dbContext.BindUserPart.Where(x => x.UserId == userid && x.PartId == partid).FirstOrDefault();
        //    //if (find == null || find == default)
        //    //{
        //    //    if (state)
        //    //    {
        //    //        var one = new BindUserPart();
        //    //        one.UserId = userid;
        //    //        one.PartId = partid;
        //    //        _dbContext.Add(one);
        //    //        await _dbContext.SaveChangesAsync();
        //    //    }
        //    //}
        //    //else
        //    //{
        //    //    if (!state)
        //    //    {
        //    //        _dbContext.Remove(find);
        //    //        await _dbContext.SaveChangesAsync();
        //    //    }
        //    //}
        //    return 1;
        //}


        /// <summary>
        /// 读取用户对象供绑定 扩展boolBind
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "read" })]
        public async Task<List<UserInfoListDto>> ReadUserForBind([FromQuery] InputUserBind input)
        {

            var users = await (from a in _dbContext.UserInfo.Where(x => x.IsEnable).WhereIf(!string.IsNullOrEmpty(input.word), x => x.UserName.Contains(input.word))
                               select new UserInfoListDto
                               {
                                   BoolBind = false,
                                   Grade = a.Grade,
                                   Id = a.Id,
                                   UserHead = a.UserHead,
                                   UserName = a.UserName
                               }).ToListAsync();
            return users;


        }


        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        /// <exception cref="PasteLoggerBoardException"></exception>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "read" })]
        public async Task<UserInfoListDto> ReadInfo()
        {
            var userid = CurrentUserId();
            var user = await _dbContext.UserInfo.Where(x => x.Id == userid).AsNoTracking().FirstOrDefaultAsync();
            if (user != null && user != default)
            {
                return ObjectMapper.Map<UserInfo, UserInfoListDto>(user);
            }
            else
            {
                throw new PasteLoggerBoardException("没有这个用户信息");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str">10进制字符串</param>
        /// <param name="lesnum">转换位数大于10</param>
        /// <returns></returns>
        [HttpGet]
        public string TestNumber(string str, int lesnum = 36)
        {

            //10==>36
            var lesslist = new System.Text.StringBuilder();
            var result = actionminus(str, lesnum);
            lesslist.Append(result.Item2);
            while (result.Item1 != "")
            {
                result = actionminus(result.Item1, lesnum);
                //lesslist.Append(result.Item2 + ".");
                lesslist.Insert(0, result.Item2 + ".");
            }

            Console.WriteLine(lesslist.ToString());

            // 36==> 10
            var countresult = new System.Text.StringBuilder();
            var lessstr = lesslist.ToString();
            var strs = lessstr.Split('.');
            for (var k = 0; k < strs.Length; k++)
            {
                countresult.Append($"{strs[k]}*{lesnum}^{(strs.Length - k - 1)}+");
            }
            return countresult.ToString().TrimEnd('+');
            //次方递减 36 ==》10 
            //3h0(36)=3*36*36+17(h)*36+0=4500(10)

            ////N次幂
            //var get = Math.Exp(5);

            ////var numrole = "100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834100187102834";

            //////12位一压缩
            ////for(var k = 0; k < numrole.Length; k+=12)
            ////{
            ////    var str = numrole.Substring(k,12);
            ////    long.TryParse(str,out var l);
            ////    if (l > 0)
            ////    {
            ////        Console.WriteLine(Convert.ToString(l,36));
            ////    }
            ////}

            ////var aaaa= System.Text.Encoding.UTF8.GetBytes(numrole);
            //return Convert.ToString(l,basea);
        }

        private (string, int) actionminus(string str, int lesnum)
        {
            var result = new System.Text.StringBuilder();
            var temp = "";
            var less = 0;
            for (var k = 0; k < str.Length; k++)
            {
                var atemp = $"{temp}{str[k]}";
                int.TryParse(atemp, out var top);
                if (top > lesnum)
                {
                    var c = top / lesnum;
                    var y = top % lesnum;
                    result.Append(c);
                    temp = $"{y}";
                    less = y;
                }
                else
                {
                    temp = atemp;
                    result.Append("0");
                    less = top;
                }
            }
            return (result.ToString().TrimStart('0'), less);
        }

        /// <summary>
        /// 格式转化
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public string ChangeDate()
        {
            var now = "2022/10/12 12:00:00";

            return DateTime.Parse(now).ToString();

        }

    }

    /// <summary>
    /// 登录的模型
    /// </summary>
    public class InputLogin
    {

        /// <summary>
        /// 
        /// </summary>
        [RegularExpression("[0-9,a-z]{3,16}@[a-z,0-9]{2,12}.[a-z]{2,5}", ErrorMessage = "账号格式有误xxx(3-16)@xxx(2-12).xxx(2-5)")]
        [Required]
        public string Email { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [RegularExpression("[0-9,a-z,A-Z]{3,32}", ErrorMessage = "密码的有效位数为3~32位数的字母数字组合")]
        [Required]
        public string Password { get; set; }

        /// <summary>
        /// 图形验证码代码
        /// </summary>
        [RegularExpression("[0-9]{4,6}", ErrorMessage = "图形验证码的值为4-6位数的数字")]
        [Required]
        public string code { get; set; }

        /// <summary>
        /// 图形验证码串号
        /// </summary>
        [RegularExpression("[0-9,a-z,A-Z]{16}", ErrorMessage = "串号为一组16位数的字母或者数字的组合")]
        [Required]
        public string guid { get; set; }
    }

}
